#include"interpreter.h"
#include<map>
#include<hash_map>
#include<malloc.h>

InterpGc::InterpGc(void *vm) {
    this->interp = vm;
    this->mempool = new std::list<Value *>();
    this->NIL = (Value *) calloc(1, sizeof (Value));
    this->NIL->t = T_Nil;
}

InterpGc::~InterpGc() {
    delete this->mempool;
    free(this->NIL);
}

Value *InterpGc::malloc(size_t valsize) {
    Value *val = (Value *) calloc(1, valsize);
    val->mark = 0;
    this->mempool->push_back(val);
    return val;
}

void InterpGc::mark() {
}

void InterpGc::markAll() {
}

void InterpGc::sweep() {
}

Interpreter::Interpreter() {
    this->gc = new InterpGc(this);
    this->NIL = ((InterpGc *)this->gc)->NIL;
    this->TopLevel = new std::hash_map<char *, Value *>();
}

Interpreter::~Interpreter() {
}

Value *Interpreter::makeInteger(int val) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_Integer;
    ret->val.ival = val;
    return ret;
}

Env *Interpreter::makeEnv(std::hash_map<char *, Value *> *current) {
    Env *ret = (Env *) ((InterpGc *)this->gc)->malloc(sizeof (Env));
    ret->uplevel = current;
    ret->hash = new std::hash_map<char *, Value *>();
    ;
    return ret;
}

Value *Interpreter::makeSymbol(char *symbol, int len) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_Symbol;
    ret->length = len;
    ret->val.symbolval = (char *) malloc(len + 1);
    memset(ret->val.symbolval, 0, len + 1);
    memcpy(ret->val.symbolval, symbol, len);

    return ret;
}

Value *Interpreter::makeString(char *str, int len) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_String;
    ret->length = len;
    ret->val.symbolval = (char *) malloc(len + 1);
    memset(ret->val.symbolval, 0, len + 1);
    memcpy(ret->val.symbolval, str, len);

    return ret;
}

Value *Interpreter::makeChar(char c) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_Char;
    ret->val.cval = c;

    return ret;
}

Value *Interpreter::makeFloat(float f) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_Float;
    ret->val.fval = f;

    return ret;
}

Value *Interpreter::makeLambda(Codes *f, std::list<Value *> *env) {
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    ret->t = T_Lambda;
    ret->val.closureval = f;
    ret->env = new std::list<Value *>(env->begin(), env->end());
    return ret;
}

Value *Interpreter::cons(Value *a, Value *b) {
    //cons (a . list) = a.list
    //cons (a . b)= a.b
    Value *ret = (Value *) ((InterpGc *)this->gc)->malloc(sizeof (Value));
    if (isList(b)) {
        ret->t = T_List;
        ret->val.listval = new std::list<Value *>(b->val.listval->begin(), b->val.listval->end());
        ret->val.listval->push_front(a);
        ret->length = b->length + 1;
    } else if (isNil(b)) {
        ret->t = T_List;
        ret->val.listval = new std::list<Value *>();
        ret->val.listval->push_front(a);
        ret->length = 1;
    } else {
        ret->t = T_Pair;
        ret->val.pairval = new std::list<Value *>();
        ret->val.pairval->push_front(b);
        ret->val.pairval->push_front(a);
        ret->length = 2;
    }
    return ret;
}

Value *Interpreter::car(Value *code) {
    if (code->length == 0) {
        //pair and list
    }
    std::list<Value *>::iterator it;
    if (isList(code)) {
        it = code->val.listval->begin();
        return *it;
    }
    if (isPair(code)) {
        it = code->val.pairval->begin();
        return *it;
    }
}

Value *Interpreter::cdr(Value *code) {
    if (code->length == 0) {
        //pair and list
    }
    if (isList(code)) {
        std::list<Value *> *tail;
        tail = code->val.listval->begin();
        if (code->length > 1) {
            tail = new std::list<Value *>(code->val.listval->begin()+1,code->val.listval->end());
        }else{
            return this->NIL;
        }
    }
    if (isPair(code)) {
        std::list<Value *>::iterator it;
        it = code->val.pairval->end();
        return *it;
    }
}

Value *Interpreter::loopup(Value *sym, Env *e) {
    Value *ret = NULL;
    std::hash_map <char *,Value *> :: const_iterator val;
    while(e!=NULL){
        val = e->hash->find(sym->val.symbolval);
        if(val != e->hash->end()){
            return val->second;
            break;
        }
        e = e->uplevel;
    }
    return this->NIL;
}



Value *Interpreter::apply(Value *func, Value *code,Env *env) {
    return this->eval(this->cons(func,code,env));
}
Value *Interpreter::run( Value *code ) {
    Env *e = (Env *)malloc(sizeof(e));
    e->hash = this->TopLevel;
    e->uplevel = NULL;
    return this->eval(code,e);
}


Value *Interpreter::eval(Value *code, Env *env) {
    switch (code->t) {
        case T_Symbol:
            return this->loopup(code, env);
            break;
        case T_Integer:
        case T_String:
        case T_Char:
        case T_Float:
        case T_Lambda:
        case T_Cfunc:
            return code;
            break;
        case T_Quote:
            return this->cdr(code);
            break;
        case T_List:
            Value head = this->car(code);
            if(isSymbol(head)){
                if(strcmp(head->val.symbolval,"lambda") == 0){
                    
                }else if(strcmp(head->val.symbolval,"if") == 0){
                }
            }
            break;
    }
}
